package com.xdclass.mobile.mobilexdclassredis.controller.redEnvelopes;

import com.xdclass.mobile.mobilexdclassredis.RedisService;
import com.xdclass.mobile.mobilexdclassredis.domain.RedPacketInfo;
import com.xdclass.mobile.mobilexdclassredis.domain.RedPacketRecord;
import com.xdclass.mobile.mobilexdclassredis.mapper.RedPacketInfoMapper;
import com.xdclass.mobile.mobilexdclassredis.mapper.RedPacketRecordMapper;
import com.xdclass.mobile.mobilexdclassredis.schedule.LockNxExJob;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.*;

/**
 * Created whit IntelliJ IDEA
 * User:杨骏杰
 * Date:2021/3/27
 * Time:14:54
 */
@RestController
public class RedPacketController {

    private static final Logger logger = LoggerFactory.getLogger(LockNxExJob.class);

    private static final String LOCK_PREFIX = "lua_";

    @Resource
    private RedisService redisService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RedPacketInfoMapper redPacketInfoMapper;

    @Resource
    private RedPacketRecordMapper redPacketRecordMapper;

    private static final String TOTAL_NUM = "_totalNum";
    private static final String TOTAL_Amount = "_totalAmount";


    /**
     * 新增红包
     * @param uid
     * @param totalNum
     * @param totalAmount
     * @return
     */
    @ResponseBody
    @RequestMapping("/addPacket")
    public String saveRedPacket(Integer uid, Integer totalNum,Integer totalAmount) {
        RedPacketInfo record = new RedPacketInfo();
        record.setUid(uid);
        record.setTotalAmount(totalAmount);
        record.setTotalPacket(totalNum);
        record.setCreateTime(new Date());
        record.setRemainingAmount(totalAmount);
        record.setRemainingPacket(totalNum);
        record.setUpdateTime(new Date());
        long redPacketId = System.currentTimeMillis(); //无法保证红包唯一性，最好使用雪花算法进行生成分布式系统唯一键
        record.setRedPacketId(redPacketId);
        redPacketInfoMapper.insert(record);
        //红包个数的key
        redisService.set(redPacketId+TOTAL_NUM,totalNum+"");
        //红包总金额
        redisService.set(redPacketId+TOTAL_Amount,totalAmount+"");
        return "success";
    }
    /**
     * 打开红包(判断红包是否存在)
     * @return
     */
    @ResponseBody
    @RequestMapping("/getPacket")
    public String getRedPacket(long redPacketId) {
        String redPacketName = redPacketId+TOTAL_NUM;
        String num = (String) redisService.get(redPacketName+"");

        if(StringUtils.isNotBlank(num)){
            return num;
        }
        return "false";
    }

    /**
     * 拆红包
     * @return
     */
    @ResponseBody
    @RequestMapping("/getRedPacketMoney")
    public String getRedPacket1(int uid,long redPacketId) {
        int randomAmount = 0;
        String redPacketName = redPacketId+TOTAL_NUM;
        String totalAmountName = redPacketId+TOTAL_Amount;
        String num = (String) redisService.get(redPacketName+"");

        if(StringUtils.isBlank(num)|| Integer.parseInt(num)==0){
            return "抱歉!红包已经抢完了";
        }
        //得到红包金额，做减免
        String totalAmount = (String) redisService.get(totalAmountName);
        if(StringUtils.isNotBlank(totalAmount)) {
            Integer totalAmountInt = Integer.parseInt(totalAmount);
            int totalNumInt = Integer.parseInt(num);
            //如果是最后一个红包则返回全部金额
            if (totalNumInt == 1) {
                randomAmount = totalAmountInt;
            } else {
                //最大的红包数
                int maxMoney = totalAmountInt / totalNumInt * 2;
                Random random =     new Random();
                //得到红包金额
                randomAmount = random.nextInt(maxMoney);
            }
        }
        //使用lua脚本将这两个命令一起执行请求
//        redisService.decr(redPacketName+"",1);
//        redisService.decr(totalAmountName,randomAmount);//redis decreby功能（做减法的）
        Object lualock = lualock(redPacketName, totalAmountName, randomAmount);
        updateRacketInDB(uid,redPacketId,randomAmount);
        return (String) lualock;
    }

    public void updateRacketInDB(Integer uid, long redPacketId,int amout){
        RedPacketRecord redPacketRecord = new RedPacketRecord();
        redPacketRecord.setUid(uid);
        redPacketRecord.setRedPacketId(redPacketId);
        redPacketRecord.setAmount(11);
        redPacketRecord.setCreateTime(new Date());
        redPacketRecordMapper.insertSelective(redPacketRecord);
//        redisService.decr(redPacketId+"_totalNum",1);
        //更改红包info表的数量
        //这里应该查出setRemainingPacket，将总数量和总金额减去
    }

    /**
     * 得到原子锁
     * @param redPacketName
     * @param totalAmountName
     * @param randomAmount
     */
    private Object lualock(String redPacketName,String totalAmountName,Integer randomAmount){
        String lock = LOCK_PREFIX + "LockNxExJob";

        boolean luaRet = false;
        try {
            luaRet = luaExpress(lock,getHostIp());

            //获取锁失败
            if (!luaRet) {
                logger.info("获取锁失败");
                String value = (String) redisService.genValue(lock);
                //打印当前占用锁的服务器IP
                logger.info("lua get lock fail,lock belong to:{}", value);
                return "重新获取";
            } else {
                //获取锁成功
                logger.info("获取锁成功");
                logger.info("lua start lock lockNxExJob success");
                redisService.decr(redPacketName+"",1);
                redisService.decr(totalAmountName,randomAmount);//redis decreby功能（做减法的）
                Thread.sleep(5000);
            }
        } catch (Exception e) {
            logger.error("lock error", e);

        } finally {
            if (luaRet) {
                logger.info("release lock success");
                redisService.remove(lock);
            }
        }
        return randomAmount+"";
    }

    /**
     * 获取lua结果
     * @param key
     * @param value
     * @return
     */
    public Boolean luaExpress(String key,String value) {
        DefaultRedisScript<Boolean> lockScript = new DefaultRedisScript<Boolean>();
        lockScript.setScriptSource(
                new ResourceScriptSource(new ClassPathResource("static/add.lua")));
        lockScript.setResultType(Boolean.class);
        // 封装参数
        List<Object> keyList = new ArrayList<Object>();
        keyList.add(key);
        keyList.add(value);
        Boolean result = (Boolean) redisTemplate.execute(lockScript, keyList);
        return result;
    }


    /**
     * 获取本机内网IP地址方法
     *
     * @return
     */
    private static String getHostIp() {
        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress ip = (InetAddress) addresses.nextElement();
                    if (ip != null
                            && ip instanceof Inet4Address
                            && !ip.isLoopbackAddress() //loopback地址即本机地址，IPv4的loopback范围是127.0.0.0 ~ 127.255.255.255
                            && ip.getHostAddress().indexOf(":") == -1) {
                        return ip.getHostAddress();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
